/* program numeros;
 var
 ate, x, soma, i: integer;
 
 begin
 x := 0;
 write('Numeros perfeitos abaixo de');
 read(ate);
 repeat
 x := x + 1;
 soma := 0;
 for i := 1 to x - 1 do
 begin
 if x/i = 0 then
 soma := soma + i;
 end;
 if soma = x then
 begin
 write(x);
 end;
 until (x > ate);
 write('Pressione qualquer tecla para finalizar…');
 end.
 */
package model;

import java.util.ArrayList;
import java.util.Iterator;
import model.Lexema;

/**
 *
 * @author Dikson
 */
public class AnalisadorLexico {

    String codigo;
    String palavra = "";
    int index;
    int linha;
    ArrayList<String> palavraReservada = new ArrayList();
    ArrayList<String> tabela = new ArrayList();
    ArrayList<Lexema> lexema = new ArrayList();
    ArrayList<Lexema> tokens1 = new ArrayList();
    ArrayList<Lexema> tokens2 = new ArrayList();
    ArrayList<Lexema> tokens3 = new ArrayList();

    public AnalisadorLexico(String pCodigo, int pLinha) {
        this.codigo = pCodigo;
        this.linha = pLinha;

    }

    public AnalisadorLexico() {

    }

    public void adicionaToken() {
        palavraReservada.add("program");
        palavraReservada.add("begin");
        palavraReservada.add("end");
        palavraReservada.add("write");
        palavraReservada.add("read");
        palavraReservada.add("if");
        palavraReservada.add("else");
        palavraReservada.add("do");
        palavraReservada.add("while");
        palavraReservada.add("var");
        palavraReservada.add("false");
        palavraReservada.add("true");
        palavraReservada.add("procedure");
        palavraReservada.add("function");
        palavraReservada.add("then");
        palavraReservada.add("or");
        palavraReservada.add("and");
        palavraReservada.add("integer");
        palavraReservada.add("read");
        palavraReservada.add("const");
        palavraReservada.add("char");
        palavraReservada.add("string");
        palavraReservada.add("real");
        palavraReservada.add("repeat");
        palavraReservada.add("break");
        palavraReservada.add("continue");
        palavraReservada.add("until");
    }

    public void analisaCodigo() {
        index = 0;
        Lexema lex;

        while (index < codigo.length()) {

            if (!codigo.isEmpty()) {

                if (Character.isWhitespace(codigo.charAt(index))) {
                    if (palavraReservada.contains(palavra)) {
                        tabela.add(palavra);
                        lex = new Lexema(Character.toString(codigo.charAt(index)), linha);
                        lexema.add(lex);

                    } else {
                        addToken(palavra);
                        lex = new Lexema(palavra, linha);
                        lexema.add(lex);
                    }
                    palavra = "";
                    proximaChar();

                } else if (Character.isLetterOrDigit(codigo.charAt(index))) {
                    palavra += codigo.charAt(index);
                    proximaChar();
                } else if (Character.valueOf(codigo.charAt(index)).equals('/') && Character.valueOf(codigo.charAt(index + 1)).equals('/')) {
                    trataComentarioDuasBarras();
                } else if (Character.valueOf(codigo.charAt(index)).equals('{')) {
                    trataComentarioChaves();
                } else {
                    addToken(palavra);
                    lex = new Lexema(palavra, linha);
                    lexema.add(lex);
                    palavra = "";
                    tabela.add(Character.toString(codigo.charAt(index)));
                    lex = new Lexema(Character.toString(codigo.charAt(index)), linha);
                    lexema.add(lex);
                    proximaChar();
                }
            }
        }

        removeEspacoVazio();
        trataAspas();
        trataAtribuicao();
        trataComparador();
        tratarAbreChaves();

    }

    public char charAtual() {
        return this.codigo.charAt(index);
    }

    public void proximaChar() {
        this.codigo.charAt(index++);
    }

    public void addToken(String token) {
        if (!token.isEmpty()) {
            tabela.add(token);
        }
    }

    public void trataAspas() {
        Iterator it = lexema.iterator();
        Lexema lex;
        String palavra = "";
        Lexema literal;

        while (it.hasNext()) {
            literal = (Lexema) it.next();
            if (literal.getSimbolo().equals("'")) {
                palavra += literal.getSimbolo();
                literal = (Lexema) it.next();
                while (!literal.getSimbolo().equals("'")) {
                    palavra += literal.getSimbolo();
                    literal = (Lexema) it.next();
                    if (!literal.getSimbolo().equals("'")) {
                        palavra += " ";
                    }
                }
                palavra += literal.getSimbolo();
                lex = new Lexema(palavra, linha);
                tokens1.add(lex);
                palavra = "";
                literal = (Lexema) it.next();
            }
            lex = new Lexema(literal.getSimbolo(), linha);
            tokens1.add(lex);
        }
    }

    public void trataAtribuicao() {
        Iterator it = tokens1.iterator();
        Lexema lex;
        String palavra = "";
        Lexema literal;

        while (it.hasNext()) {
            literal = (Lexema) it.next();
            if (literal.getSimbolo().equals(":")) {
                palavra += literal.getSimbolo();
                literal = (Lexema) it.next();
                if (literal.getSimbolo().equals("=")) {
                    palavra += literal.getSimbolo();
                    lex = new Lexema(palavra, linha);
                    tokens2.add(lex);
                } else {
                    lex = new Lexema(palavra, linha);
                    tokens2.add(lex);
                    tokens2.add(literal);
                }

                literal = (Lexema) it.next();
            }
            lex = new Lexema(literal.getSimbolo(), linha);
            tokens2.add(lex);
            palavra = "";
        }
    }

    public void trataComparador() {
        Iterator it = tokens2.iterator();
        Lexema lex;
        String palavra = "";
        Lexema literal;

        while (it.hasNext()) {
            literal = (Lexema) it.next();
            if (literal.getSimbolo().equals("<")) {
                palavra += literal.getSimbolo();
                literal = (Lexema) it.next();
                if (literal.getSimbolo().equals("=")) {
                    palavra += literal.getSimbolo();
                }
                lex = new Lexema(palavra, linha);
                tokens3.add(lex);
            } else if (literal.getSimbolo().equals(">")) {
                palavra += literal.getSimbolo();
                literal = (Lexema) it.next();
                if (literal.getSimbolo().equals("=")) {
                    palavra += literal.getSimbolo();
                }
                lex = new Lexema(palavra, linha);
                tokens3.add(lex);
                literal = (Lexema) it.next();
            }
            tokens3.add(literal);
            palavra = "";
        }
    }

    // tratar comentário com chaves
    public void tratarAbreChaves() {
        int inicio = 0, fim = 0, cont = 0;
        Iterator it = tokens3.iterator();
        String palavra = "";
        while (it.hasNext()) {
            palavra = (String) it.next();
            if (palavra.equals("{")) {
                inicio = cont;
            }
            if (palavra.equals("}")) {
                fim = cont;
            }
            cont++;
        }
        // mensagens de erro
        if (inicio != 0 && fim == 0);//emitir mensagem de erro avisando que não fechou chaves
        if (inicio == 0 && fim != 0);//emitir mensagem de erro avisando que encontrou chaves fechando sem ter uma abrindo
        if (inicio != 0 && fim != 0) {
            for (int i = fim - 1; i > inicio; i--) {
                tokens3.remove(i);
            }
        }
    }

    // tratar comentários (* *)
    public void tratarComentarioParenteses() {
        int inicio = 0, fim = 0, cont = 0;
        Iterator it = tokens3.iterator();
        String palavra = "";
        while (it.hasNext()) {
            palavra = (String) it.next();
            if (palavra.equals("(*")) {
                inicio = cont;
            }
            if (palavra.equals("*)")) {
                fim = cont;
            }
            cont++;
        }
        // mensagens de erro
        if (inicio != 0 && fim == 0);//emitir mensagem de erro avisando que não fechou chaves
        if (inicio == 0 && fim != 0);//emitir mensagem de erro avisando que encontrou chaves fechando sem ter uma abrindo
        if (inicio != 0 && fim != 0) {
            for (int i = fim - 1; i > inicio; i--) {
                tokens3.remove(i);
            }
        }
    }

    public String getLexema() {
        Iterator it = tokens3.iterator();
        String palavra = "";
        while (it.hasNext()) {
            return (String) it.next();
        }
        return "";
    }

//    public void testeLexema() {
//        Iterator it = tokens3.iterator();
//        Lexema palavra;
//        while (it.hasNext()) {
//            palavra = (Lexema) it.next();
//            System.out.println("Linha: " + palavra.getLinha() + " - Lexema: " + palavra.getSimbolo());
//            //  tb.analisa(palavra);
//        }
//    }
    public void removeEspacoVazio() {
        Iterator it = lexema.iterator();
        Lexema palavra;
        while (it.hasNext()) {
            palavra = (Lexema) it.next();
            if (palavra.getSimbolo().equals("")) {
                it.remove();
            }
        }
    }

    public void trataComentarioDuasBarras() {
        while (!(Character.valueOf(codigo.charAt(index)).equals('\n'))) {
            proximaChar();
        }
    }

    public void trataComentarioChaves() {
        while (!(Character.valueOf(codigo.charAt(index)).equals('}'))) {
            proximaChar();
        }
    }
}
